#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <stdlib.h>

#define FILE_NAME_TO_COMPILE "/home/dgdiniz/z80filetocompile.asm"
#define COMPILED_PROGRAM_NAME "/home/dgdiniz/z80program.bin"


MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    ui->textEdit->setLineWrapMode(QTextEdit::NoWrap);

    CPU = new cpu(ui->textEdit);

    //CPU->test_registers();
    //CPU->test_processor();
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::openBinary(const QString fileName){
    QFile file(fileName);

    ui->textEdit->insertPlainText(fileName);

    if (!file.open(QFile::ReadOnly)) {
        QMessageBox::warning(this, tr("SDI"),
                             tr("Cannot read binary file %1 :\n%2.")
                             .arg(fileName)
                             .arg(file.errorString()));
        return;
    }

    ui->hexeditor->setData(file.readAll());

    CPU->reset();
    CPU->load_program(fileName.toAscii());
    updateWindowRegisters();
    ui->hexeditor->selectArea(CPU->getPC(), 3);

    file.close();
}

void MainWindow::on_actionOpenBinary_triggered()
{
    QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"),"",tr("Files (*.*)"));

    openBinary(fileName);
}

void MainWindow::on_actionOpen_Z80_Code_triggered()
{
    QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"),"",tr("Files (*.*)"));

    QFile file(fileName);
    if (!file.open(QFile::ReadOnly)) {
        QMessageBox::warning(this, tr("SDI"),
                             tr("Cannot read file %1:\n%2.")
                             .arg(fileName)
                             .arg(file.errorString()));
        return;
    }

    ui->textCode->setText(file.readAll());
}

void MainWindow::on_actionRun_triggered()
{
    CPU->z80_reset();
    CPU->run_loaded_program();
    //CPU->registersDump();
    updateWindowRegisters();
}


void MainWindow::updateWindowRegisters(){

    ui->txtRegA->setText(QString::number(CPU->getReg(_A)));
    ui->txtRegF->setText(QString::number(CPU->getReg(_F)));
    ui->txtRegB->setText(QString::number(CPU->getReg(_B)));
    ui->txtRegC->setText(QString::number(CPU->getReg(_C)));
    ui->txtRegD->setText(QString::number(CPU->getReg(_D)));
    ui->txtRegE->setText(QString::number(CPU->getReg(_E)));
    ui->txtRegH->setText(QString::number(CPU->getReg(_H)));
    ui->txtRegL->setText(QString::number(CPU->getReg(_L)));
    ui->txtRegPC->setText(QString::number(CPU->getPC()));
    ui->txtRegSP->setText(QString::number(CPU->getSP()));
    ui->txtRegAF->setText(QString::number(CPU->getRegPair(_AF)));
    ui->txtRegBC->setText(QString::number(CPU->getRegPair(_BC)));
    ui->txtRegDE->setText(QString::number(CPU->getRegPair(_DE)));
    ui->txtRegHL->setText(QString::number(CPU->getRegPair(_HL)));
    ui->txtRegIX->setText(QString::number(CPU->getRegPair(_IX)));
    ui->txtRegIY->setText(QString::number(CPU->getRegPair(_IY)));
    ui->txtRegCarry_c->setText(QString::number(bool(CPU->getReg(_F) & 0x1)));
    ui->txtRegCarry_n->setText(QString::number(bool(CPU->getReg(_F) & 0x2)));
    ui->txtRegCarry_pv->setText(QString::number(bool(CPU->getReg(_F) & 0x4)));
    ui->txtRegCarry_f3->setText(QString::number(bool(CPU->getReg(_F) & 0x5)));
    ui->txtRegCarry_h->setText(QString::number(bool(CPU->getReg(_F) & 0x16)));
    ui->txtRegCarry_f5->setText(QString::number(bool(CPU->getReg(_F) & 0x32)));
    ui->txtRegCarry_z->setText(QString::number(bool(CPU->getReg(_F) & 0x64)));
    ui->txtRegCarry_s->setText(QString::number(bool(CPU->getReg(_F) & 0x128)));
}



void MainWindow::on_actionStep_triggered()
{
    CPU->cpu_step();
    updateWindowRegisters();
    ui->hexeditor->selectArea(CPU->getPC(), 3);
}


int MainWindow::compileCode() {
    int compileResult = 0;
    QFile file(FILE_NAME_TO_COMPILE);
    QString compileCall;

    if (!file.open(QFile::ReadWrite | QFile::Truncate)) {
        QMessageBox::warning(this, tr("SDI"),
                             tr("Cannot read file %1:\n%2.")
                             .arg(FILE_NAME_TO_COMPILE)
                             .arg(file.errorString()));
        return 1;
    }

    file.write(ui->textCode->toPlainText().toAscii());
    file.flush();
    file.close();

    compileCall = "z80asm -o " COMPILED_PROGRAM_NAME  " "   FILE_NAME_TO_COMPILE;

    system(compileCall.toAscii());

    ui->textEdit->insertPlainText("Compilation completed with success\n");

    return compileResult;
}

void MainWindow::on_actionCompile_triggered()
{
    int compileResult;

    compileResult = compileCode();

    if (compileResult == 0)
    {
        openBinary(COMPILED_PROGRAM_NAME);
    }
}

void MainWindow::on_txtRegA_textChanged(const QString &arg1)
{
    CPU->setReg(_A, arg1.toUShort());
}

void MainWindow::on_txtRegB_textChanged(const QString &arg1)
{
    CPU->setReg(_B, arg1.toUShort());
}

void MainWindow::on_txtRegC_textChanged(const QString &arg1)
{
    CPU->setReg(_C, arg1.toUShort());
}

void MainWindow::on_txtRegD_textChanged(const QString &arg1)
{
    CPU->setReg(_D, arg1.toUShort());
}

void MainWindow::on_txtRegE_textChanged(const QString &arg1)
{
    CPU->setReg(_E, arg1.toUShort());
}

void MainWindow::on_txtRegH_textChanged(const QString &arg1)
{
    CPU->setReg(_H, arg1.toUShort());
}

void MainWindow::on_txtRegL_textChanged(const QString &arg1)
{
    CPU->setReg(_L, arg1.toUShort());
}

void MainWindow::on_txtRegBC_textChanged(const QString &arg1)
{
    CPU->setRegPair(_BC, arg1.toUShort());
}

void MainWindow::on_txtRegDE_textChanged(const QString &arg1)
{
    CPU->setRegPair(_DE, arg1.toUShort());
}

void MainWindow::on_txtRegHL_textChanged(const QString &arg1)
{
    CPU->setRegPair(_HL, arg1.toUShort());
}

void MainWindow::on_txtRegIX_textChanged(const QString &arg1)
{
    CPU->setRegPair(_IX, arg1.toUShort());
}

void MainWindow::on_txtRegIY_textChanged(const QString &arg1)
{
    CPU->setRegPair(_IY, arg1.toUShort());
}

void MainWindow::on_txtRegPC_textChanged(const QString &arg1)
{
    CPU->setPC(arg1.toUShort());
}

void MainWindow::on_txtRegSP_textChanged(const QString &arg1)
{
    CPU->setSP(arg1.toUShort());
}
